# !/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
===========================
@Time : 2022/10/6 0006 4:59
@Author : 测试开发工程师
@File : 20. 接口鉴权的多种情况与解决方案.py
@Software: PyCharm
============================
"""

"""
接口鉴权： （权限控制 和 信息管理）
    接口自动化测试中的身份认证
    
接口鉴权通用的解决方案：
    认证信息的获取（登录成功）
    认证信息的携带（接口请求中携带）

后端接口鉴权常用方法：
    cookie: 
        1. 携带身份信息请求认证(获取 set_cookie)
        2. 之后的每次请求都携带 cookie。cookie 记录在请求头中
        
    token:
        1. 携带身份信息认证
        2. 之后的每次请求都携带 token 认证
        3. 可能记录在请求头（最常用：飞书），也可能记录在 url 中（企业微信）。依据项目而定
        
    Basic Auth:
        每次请求携带用户的 username 和 password ，并对其信息加密（base64，很好被破解）
        
    outh(2):
        1. 携带身份信息请求认证
        2. 服务端向指定回调地址回传 code
        3. 通过 code 获取 token
        4. 之后的请求信息都携带 token
        典型产品： 微信自动化测试
"""

# ==================================== cookie 鉴权 ======================================
"""
1. cookie 的获取（根据接口文档获取）
2. 发送携带 cookie 的请求
    直接通过 cookie 参数
    通过 Session() 对象 
"""

import requests


class TestCookieVerify:
    # ================================================ 直接通过 cookie 参数 ============================================
    def test_cookies_by_write(self):
        # 简单场景，直接写入 cookie
        url = 'https://httpbin.ceshiren.com/cookies'
        res = requests.get(url)
        # 结果为： {'cookies': {}}
        print(res.json())
        # 传入 cookie 后
        cookie_res = requests.get(url, verify=False, cookies={'hogwarts': 'AD'})
        # 结果为： {'cookies': {'hogwarts': 'AD'}}
        print(cookie_res.json())

    # =========================================== 通过 Session() 对象（常用） ==========================================
    # ========================== 不使用 session() 时，print(res2.json()) 为 {'cookies': {}} ============================
    def test_cookies_without_session(self):
        # 获取 session 的实例，需要通过 Session() 保持会话
        # 即为认证之后，之后所有的实例都会携带 cookie
        # 可以模仿用户在浏览器的操作
        req = requests.Session()
        # 第一次登录，获取 cookie
        set_url = 'https://httpbin.ceshiren.com/cookies/set/hogwarts/ad'
        res1 = req.get(set_url, verify=False)
        # 结果为： {'cookies': {'hogwarts': 'ad'}}
        print(res1.json())
        # 第二次请求的时候，即可携带 cookie  信息
        url = 'https://httpbin.ceshiren.com/cookies'
        res2 = req.get(url, verify=False)
        # 结果为： {'cookies': {'hogwarts': 'ad'}}
        print(res2.json())


# ======================================= token 鉴权 ====================================================
# ======================================= 每个公司每个项目可能都不同 ==============================================
"""
1. token 的获取（根据接口文档获取）
2. 发送携带 token 的请求（根据接口文档获取）
"""


class TestTokenVerify:
    def test_litemall_token(self):
        # 登录 获取 token
        url = 'http://litemall.hogwarts.ceshiren.com/admin/auth/login'
        user_data = {'username': 'admin123', 'password': 'admin123', 'code': ''}
        r = requests.post(url, json=user_data, verify=False)
        print(r.json())
        self.token = r.json()['data']['token']
        # 结果为： ba35daff-2bef-4ffe-9c72-e946b6cfe880
        print(self.token)
        # 之后的请求均携带 token
        good_list_url = 'http://litemall.hogwarts.ceshiren.com/admin/goods/list'
        goods_data = {'name': 'hogwarts', 'order': 'desc', 'sort': 'add_time'}
        r_token = requests.get(good_list_url, json=goods_data, headers={'X-Litemall-Admin-Token': self.token},
                               verify=False)
        # 结果为 ： {'errno': 0, 'data': {'total': 512, 'pages': 52, 'limit': 10, 'page': 1, 'list': [{'id': 1183302, 'goodsSn': '9008', 'name': 'AD_ad', 'categoryId': 0, 'brandId': 0, 'gallery': [], 'keywords': '', 'brief': '', 'isOnSale': True, 'sortOrder': 100, 'picUrl': '', 'shareUrl': '', 'isNew': True, 'isHot': False, 'unit': '’件‘', 'counterPrice': 0.0, 'retailPrice': 66.0, 'addTime': '2022-10-05 11:46:03', 'updateTime': '2022-10-05 13:28:18', 'deleted': False}, {'id': 1183301, 'goodsSn': '1111114', 'name': 'hogwarts1111114', 'categoryId': 0, 'brandId': 0, 'gallery': [], 'keywords': '', 'brief': '', 'isOnSale': True, 'sortOrder': 100, 'picUrl': '', 'isNew': True, 'isHot': True, 'unit': '’件‘', 'counterPrice': 1234.0, 'retailPrice': 0.0, 'addTime': '2022-10-05 09:38:33', 'updateTime': '2022-10-05 09:38:33', 'deleted': False}, {'id': 1183287, 'goodsSn': '6111', 'name': '商品_6111', 'categoryId': 0, 'brandId': 0, 'gallery': [], 'keywords': '', 'brief': '', 'isOnSale': True, 'sortOrder': 100, 'picUrl': '', 'shareUrl': '', 'isNew': True, 'isHot': True, 'unit': '’件‘', 'counterPrice': 193.0, 'retailPrice': 25.0, 'addTime': '2022-10-04 03:03:08', 'updateTime': '2022-10-05 13:28:00', 'deleted': False}, {'id': 1183286, 'goodsSn': '3913', 'name': '商品_3913', 'categoryId': 0, 'brandId': 0, 'gallery': [], 'keywords': '', 'brief': '', 'isOnSale': True, 'sortOrder': 100, 'picUrl': '', 'isNew': True, 'isHot': True, 'unit': '’件‘', 'counterPrice': 109.0, 'retailPrice': 0.0, 'addTime': '2022-10-04 03:01:29', 'updateTime': '2022-10-04 03:01:29', 'deleted': False}, {'id': 1183285, 'goodsSn': '9173', 'name': '商品_9173', 'categoryId': 0, 'brandId': 0, 'gallery': [], 'keywords': '', 'brief': '', 'isOnSale': True, 'sortOrder': 100, 'picUrl': '', 'isNew': True, 'isHot': True, 'unit': '’件‘', 'counterPrice': 157.0, 'retailPrice': 0.0, 'addTime': '2022-10-04 02:58:30', 'updateTime': '2022-10-04 02:58:30', 'deleted': False}, {'id': 1183270, 'goodsSn': '9009872', 'name': '好爽可乐11111', 'categoryId': 0, 'brandId': 0, 'gallery': [], 'keywords': '', 'brief': '', 'isOnSale': True, 'sortOrder': 100, 'picUrl': '', 'isNew': True, 'isHot': False, 'unit': '’件‘', 'counterPrice': 0.0, 'retailPrice': 5.0, 'addTime': '2022-10-03 11:31:58', 'updateTime': '2022-10-03 11:31:58', 'deleted': False}, {'id': 1183271, 'goodsSn': '9009872', 'name': '好爽可乐11112', 'categoryId': 0, 'brandId': 0, 'gallery': [], 'keywords': '', 'brief': '', 'isOnSale': True, 'sortOrder': 100, 'picUrl': '', 'isNew': True, 'isHot': False, 'unit': '’件‘', 'counterPrice': 0.0, 'retailPrice': 5.0, 'addTime': '2022-10-03 11:31:58', 'updateTime': '2022-10-03 11:31:58', 'deleted': False}, {'id': 1183269, 'goodsSn': '9009872', 'name': '好爽可乐1112', 'categoryId': 0, 'brandId': 0, 'gallery': [], 'keywords': '', 'brief': '', 'isOnSale': True, 'sortOrder': 100, 'picUrl': '', 'isNew': True, 'isHot': False, 'unit': '’件‘', 'counterPrice': 0.0, 'retailPrice': 5.0, 'addTime': '2022-10-03 11:27:56', 'updateTime': '2022-10-03 11:27:56', 'deleted': False}, {'id': 1183268, 'goodsSn': '9009872', 'name': '好爽可乐1111', 'categoryId': 0, 'brandId': 0, 'gallery': [], 'keywords': '', 'brief': '', 'isOnSale': True, 'sortOrder': 100, 'picUrl': '', 'isNew': True, 'isHot': False, 'unit': '’件‘', 'counterPrice': 0.0, 'retailPrice': 5.0, 'addTime': '2022-10-03 11:27:55', 'updateTime': '2022-10-03 11:27:55', 'deleted': False}, {'id': 1183266, 'goodsSn': '9009872', 'name': '好爽可乐111', 'categoryId': 0, 'brandId': 0, 'gallery': [], 'keywords': '', 'brief': '', 'isOnSale': True, 'sortOrder': 100, 'picUrl': '', 'isNew': True, 'isHot': False, 'unit': '’件‘', 'counterPrice': 0.0, 'retailPrice': 5.0, 'addTime': '2022-10-03 11:18:12', 'updateTime': '2022-10-03 11:18:12', 'deleted': False}]}, 'errmsg': '成功'}
        print(r_token.json())
        assert r_token.json()['errno'] == 0
        assert r_token.json()['data']['list'][0]['id'] == 1183302


# =========================================== auth 鉴权（了解） ============================================
"""
在基本 HTTP 身份验证中，请求包含格式为标头字段 Authorrization:Basic
其中 credentials 是 ID 和密码的 Base64 编码，由单个冒号连接
"""
import requests
from requests.auth import HTTPBasicAuth


class TestAuthVerify:
    def test_basic_auth(self):
        # 表示访问一个需要 BasicAuth 认证的路径
        # username=用户名,password=密码
        # 如果不使用 basic auth ，则会失败
        r = requests.get('https://httpbin.ceshiren.com/basic-auth/username/password', verify=False,
                         auth=HTTPBasicAuth('username', 'password'))
        # 结果为： {'authenticated': True, 'user': 'username'}
        print(r.json())
